﻿// Decompiled with JetBrains decompiler
// Type: Netick.Unity.NetworkTransform
// Assembly: Netick.Unity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E128C7FD-39ED-4452-86AC-6EC748457030
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.xml

using System.Numerics;
using UnityEngine;

#nullable disable
namespace Netick.Unity;

/// <summary>
/// This component is used to replicate the position and rotation of an object.
/// </summary>
[IgnoreCodeGen]
[ExecutionOrder(-1000)]
[AddComponentMenu("Netick/Network Transform")]
[RequireComponent(typeof (Transform))]
[DisallowMultipleComponent]
public class NetworkTransform : NetworkBehaviour, IClientSimulationCallbacks
{
  internal const string ErrorMsg = "You must enable PhysicsPrediction in (Netick -> Settings) if you want Network Rigidbody to work correctly under Client-Side Prediction.";
  internal const int OffsetToPos = 0;
  internal const int OffsetToRot = 3;
  internal const int OffsetToTeleportTick = 7;
  internal const int OffsetToVelocity3D = 8;
  internal const int OffsetToAngularVelocity3D = 11;
  internal const int OffsetToIsKinematic3D = 14;
  internal const int OffsetToVelocity2D = 8;
  internal const int OffsetToAngularVelocity2D = 10;
  internal const int OffsetToIsKinematic2D = 11;
  public Transform RenderTransform;
  [HideInInspector]
  [SerializeField]
  public float TeleportDistance = 50f;
  [SerializeField]
  private int PositionPrecision = 3;
  [SerializeField]
  private NetworkTransformRepConditions Settings = NetworkTransformRepConditions.SyncPosition | NetworkTransformRepConditions.SyncRotation | NetworkTransformRepConditions.CompressPosition | NetworkTransformRepConditions.CompressRotation | NetworkTransformRepConditions.CompressRotationAggressively;
  [SerializeField]
  protected TransformSpace TransformSpace = TransformSpace.World;
  [SerializeField]
  private bool UseForAOIPosition = true;
  [HideInInspector]
  [SerializeField]
  private bool EnablePredictionErrorCorrectionSmoothing;
  public float CorrectionMultiplier = 3f;
  public float TeleportErrorThreshold = 50f;
  private NetworkTransformErrorCorrector _errorCorrector;
  [SerializeField]
  private InterpolationSource _interpolationSource;
  private AdaptiveRemoteInterpolation _adaptiveRemoteInterpolation;
  private Transform _trans;
  protected bool _syncPosition;
  protected bool _syncRot;
  protected float _posPrecision;
  protected float _posInversePrecision;
  protected float _rotPrecision;
  protected float _rotInversePrecision;
  private int _teleportTickClient;
  private Tick _becameInterestedTick;
  private Vector3 _lastPos = Vector3.positiveInfinity;
  private Quaternion _lastRot = Quaternion.identity;

  public InterpolationSource InterpolationSource
  {
    get => this._interpolationSource;
    set => this._interpolationSource = value;
  }

  internal unsafe int TeleportTick
  {
    get => this.StatePtr[7];
    set
    {
      if (this.IsClient)
        this._teleportTickClient = value;
      else
        Entity.InternalDirtify((INetickNetworkScript) this, &value, this.StatePtr + 7, 1, 0);
    }
  }

  public unsafe Vector3 Position => NetickUnityUtils.GetVector3(this.StatePtr, this._posPrecision);

  public unsafe Quaternion Rotation
  {
    get
    {
      return (this.Settings & NetworkTransformRepConditions.CompressRotationAggressively) == NetworkTransformRepConditions.CompressRotationAggressively ? NetickUnityUtils.GetQuaternionCompressed(this.StatePtr + 3) : NetickUnityUtils.GetQuaternion(this.StatePtr + 3, this._rotPrecision);
    }
  }

  public override int InternalGetStateSizeWords() => 9;

  /// <summary>
  /// Instantly moves the object. By calling this method, the object won't be interpolated for one tick.
  /// </summary>
  /// <param name="position"></param>
  public void Teleport(Vector3 position)
  {
    this.transform.position = position;
    this.TeleportTick = this.Sandbox.Tick.Value + 1;
  }

  /// <summary>
  /// Instantly moves the object. By calling this method, the object won't be interpolated for one tick.
  /// </summary>
  /// <param name="position"></param>
  public void Teleport(Vector3 position, Quaternion rotation)
  {
    this.transform.position = position;
    this.transform.rotation = rotation;
    this.TeleportTick = this.Sandbox.Tick.Value + 1;
  }

  /// <summary>
  /// Instantly moves the object. By calling this method, the object won't be interpolated for one tick.
  /// </summary>
  /// <param name="position"></param>
  public void Teleport(Quaternion rotation)
  {
    this.transform.rotation = rotation;
    this.TeleportTick = this.Sandbox.Tick.Value + 1;
  }

  private void Awake() => this._trans = this.GetComponent<Transform>();

  public override unsafe void InternalReset()
  {
    this._trans = this.GetComponent<Transform>();
    this._adaptiveRemoteInterpolation = this.Entity.AdaptiveRemoteInterpolation;
    this._posInversePrecision = Mathf.Pow(10f, (float) this.PositionPrecision);
    this._posPrecision = 1f / this._posInversePrecision;
    this._rotInversePrecision = this._posInversePrecision;
    this._rotPrecision = this._posPrecision;
    this._syncPosition = (this.Settings & NetworkTransformRepConditions.SyncPosition) == NetworkTransformRepConditions.SyncPosition;
    this._syncRot = (this.Settings & NetworkTransformRepConditions.SyncRotation) == NetworkTransformRepConditions.SyncRotation;
    int num = (this.Settings & NetworkTransformRepConditions.CompressPosition) == NetworkTransformRepConditions.CompressPosition ? 1 : 0;
    bool flag1 = (this.Settings & NetworkTransformRepConditions.CompressRotation) == NetworkTransformRepConditions.CompressRotation;
    bool flag2 = (this.Settings & NetworkTransformRepConditions.CompressRotationAggressively) == NetworkTransformRepConditions.CompressRotationAggressively;
    if (num == 0)
    {
      this._posPrecision = -1f;
      this._posInversePrecision = -1f;
    }
    if (!flag1)
    {
      this._rotPrecision = -1f;
      this._rotInversePrecision = -1f;
    }
    if (this.IsClient)
    {
      if (this._errorCorrector == null && this.EnablePredictionErrorCorrectionSmoothing)
      {
        if (!Network.Config.AccurateLocalInterpolation)
          Debug.LogError((object) "Netick: for Prediction Error Correction Smoothing to work correctly, please enable Accurate Local Interpolation in Netick Settings/Config");
        this._errorCorrector = new NetworkTransformErrorCorrector();
      }
      if (this._errorCorrector != null)
        this._errorCorrector.TransformErrorCorrector.Init(this.transform.position, this.transform.rotation);
    }
    if (this.TransformSpace == TransformSpace.Local)
    {
      if (this._syncPosition)
        NetickUnityUtils.SetVector3(this.StatePtr, this.transform.localPosition, this._posInversePrecision);
      if (this._syncRot)
      {
        if (flag2)
          NetickUnityUtils.SetQuaternionCompressed(this.StatePtr + 3, this.transform.localRotation);
        else
          NetickUnityUtils.SetQuaternion(this.StatePtr + 3, this.transform.localRotation, this._rotInversePrecision);
      }
    }
    else
    {
      if (this._syncPosition)
        NetickUnityUtils.SetVector3(this.StatePtr, this.transform.position, this._posInversePrecision);
      if (this._syncRot)
      {
        if (flag2)
          NetickUnityUtils.SetQuaternionCompressed(this.StatePtr + 3, this.transform.rotation);
        else
          NetickUnityUtils.SetQuaternion(this.StatePtr + 3, this.transform.rotation, this._rotInversePrecision);
      }
    }
    if (!this.Sandbox.IsServer)
      return;
    for (int index = 0; index < 7; ++index)
      this.Entity.MarkAltered(this.StatePtr + index);
  }

  public override void NetworkStart()
  {
    this._lastPos = new Vector3();
    this._lastRot = Quaternion.identity;
    if (this._errorCorrector == null)
      return;
    this.Sandbox.Engine.ClientSimulationCallbacks.Add((IClientSimulationCallbacks) this);
  }

  public override void NetworkDestroy()
  {
    if (this._errorCorrector == null)
      return;
    this.Sandbox.Engine.ClientSimulationCallbacks.Remove((IClientSimulationCallbacks) this);
  }

  void IClientSimulationCallbacks.OnPreRollback()
  {
    this._errorCorrector.TransformErrorCorrector.OnPreRollback(this.transform.position, this.transform.rotation);
  }

  void IClientSimulationCallbacks.OnPostResimulation()
  {
    this._errorCorrector.TransformErrorCorrector.OnPostResimulation(this.transform.position, this.transform.rotation);
  }

  public override void NetworkFixedUpdate()
  {
    if (!((UnityEngine.Object) this.RenderTransform != (UnityEngine.Object) null))
      return;
    if (this._syncPosition)
      this.RenderTransform.transform.position = this._trans.position;
    if (!this._syncRot)
      return;
    this.RenderTransform.transform.rotation = this._trans.rotation;
  }

  public override void NetworkRender()
  {
    if (!((UnityEngine.Object) this.RenderTransform != (UnityEngine.Object) null))
      return;
    Vector3 pos;
    Quaternion rot;
    this.Render(out pos, out rot, this._interpolationSource);
    if (this._syncPosition)
      this.RenderTransform.position = pos;
    if (!this._syncRot)
      return;
    this.RenderTransform.rotation = rot;
  }

  public bool GetInterpolatedPosRot(out Vector3 pos, out Quaternion rot)
  {
    return this.GetInterpolatedPosRot(out pos, out rot, this._interpolationSource);
  }

  public bool GetInterpolatedPosRot(
    out Vector3 pos,
    out Quaternion rot,
    InterpolationSource interpolationSource)
  {
    return this.GetInterpolatedPosRot(out pos, out rot, interpolationSource);
  }

  private unsafe bool Render(
    out Vector3 pos,
    out Quaternion rot,
    InterpolationSource interpolationSource)
  {
    pos = this.transform.position;
    rot = this.transform.rotation;
    bool isServer = this.IsServer;
    Interpolation interpolation;
    if (isServer)
    {
      interpolation = (Interpolation) this.Object.Engine.LocalInterpolation;
    }
    else
    {
      switch (interpolationSource)
      {
        case InterpolationSource.PredictedSnapshot:
          interpolation = (Interpolation) this.Object.Engine.LocalInterpolation;
          break;
        case InterpolationSource.RemoteSnapshot:
          interpolation = this._adaptiveRemoteInterpolation != null ? (Interpolation) this._adaptiveRemoteInterpolation : (Interpolation) this.Object.Engine.RemoteInterpolation;
          break;
        default:
          interpolation = !this.Entity.IsPredicted ? (this._adaptiveRemoteInterpolation != null ? (Interpolation) this._adaptiveRemoteInterpolation : (Interpolation) this.Object.Engine.RemoteInterpolation) : (Interpolation) this.Object.Engine.LocalInterpolation;
          break;
      }
    }
    if (!interpolation.HasSnapshots)
      return false;
    bool flag = (this.Settings & NetworkTransformRepConditions.CompressRotationAggressively) == NetworkTransformRepConditions.CompressRotationAggressively;
    long num = this.Entity.StateOffsetBytes + ((sbyte*) this.StatePtr - (sbyte*) this.Entity.StatePtr);
    float alpha = interpolation.Alpha;
    byte* ptr1 = (byte*) interpolation.FromSnapshot.Blocks[this.Entity.BlockIndex].Ptr;
    byte* ptr2 = (byte*) interpolation.ToSnapshot.Blocks[this.Entity.BlockIndex].Ptr;
    int* data1 = (int*) (ptr1 + num);
    int* data2 = (int*) (ptr2 + num);
    Vector3 vector3_1 = NetickUnityUtils.GetVector3(data1, this._posPrecision);
    Vector3 vector3_2 = NetickUnityUtils.GetVector3(data2, this._posPrecision);
    Tick tick1 = new Tick(data1[7]);
    Tick tick2 = new Tick(data2[7]);
    Vector3 vector3_3 = Vector3.Lerp(vector3_1, vector3_2, alpha);
    Quaternion quaternion1 = new Quaternion();
    bool syncPosition = this._syncPosition;
    bool syncRot = this._syncRot;
    Quaternion quaternion2 = new Quaternion();
    Quaternion quaternion3 = new Quaternion();
    if (this._syncRot)
    {
      if (flag)
      {
        quaternion2 = NetickUnityUtils.GetQuaternionCompressed(data1 + 3);
        Quaternion quaternionCompressed = NetickUnityUtils.GetQuaternionCompressed(data2 + 3);
        quaternion1 = Quaternion.Slerp(quaternion2, quaternionCompressed, alpha);
      }
      else
      {
        quaternion2 = NetickUnityUtils.GetQuaternion(data1 + 3, this._rotPrecision);
        Quaternion quaternion4 = NetickUnityUtils.GetQuaternion(data2 + 3, this._rotPrecision);
        quaternion1 = Quaternion.Slerp(quaternion2, quaternion4, alpha);
      }
    }
    if (!isServer && (this.Engine.Tick - 1).Value < this._teleportTickClient)
    {
      this.ExecuteTeleport(syncPosition, syncRot, ref pos, ref rot, this.transform.position, this.transform.rotation);
      return true;
    }
    if (!isServer)
    {
      if ((Tick) (this.Object.Engine.RemoteInterpolation.To - 1).Value < tick2 && (Tick) this._teleportTickClient != tick2 || (double) Vector3.Distance(vector3_1, vector3_2) >= (double) this.TeleportDistance)
      {
        this.ExecuteTeleport(syncPosition, syncRot, ref pos, ref rot, vector3_1, quaternion2);
        return true;
      }
    }
    else if ((this.Engine.Tick - 1).Value < this.TeleportTick || (double) Vector3.Distance(vector3_1, vector3_2) >= (double) this.TeleportDistance)
    {
      this.ExecuteTeleport(syncPosition, syncRot, ref pos, ref rot, vector3_1, quaternion2);
      return true;
    }
    if (this.IsProxy && this._becameInterestedTick > interpolation.From)
    {
      this.ExecuteTeleport(syncPosition, syncRot, ref pos, ref rot, vector3_1, quaternion2);
      return true;
    }
    if (interpolation == this.Object.Engine.LocalInterpolation)
    {
      if (!isServer)
      {
        NetworkTransformErrorCorrector errorCorrector = this._errorCorrector;
        if (errorCorrector != null && this.EnablePredictionErrorCorrectionSmoothing)
        {
          Vector3 posInterpolatedValue = vector3_3;
          Quaternion rotInterpolatedValue = quaternion1;
          errorCorrector.TransformErrorCorrector.Render(ref posInterpolatedValue, ref rotInterpolatedValue, this.CorrectionMultiplier, this.TeleportErrorThreshold, this.Sandbox.DeltaTime);
          if (syncPosition)
            vector3_3 = posInterpolatedValue;
          if (syncRot)
            quaternion1 = rotInterpolatedValue;
        }
      }
      if ((UnityEngine.Object) this.transform.parent == (UnityEngine.Object) null)
      {
        if (syncPosition)
          pos = vector3_3;
        if (syncRot)
          rot = quaternion1;
      }
      else if ((UnityEngine.Object) this.Object.Parent != (UnityEngine.Object) null && (UnityEngine.Object) this.Object.Parent.AttachedNetworkTransform != (UnityEngine.Object) null)
      {
        if (this.TransformSpace == TransformSpace.World)
        {
          if (syncPosition)
            pos = vector3_3;
          if (syncRot)
            rot = quaternion1;
        }
        else
        {
          Vector3 pos1;
          Quaternion rot1;
          this.Object.Parent.AttachedNetworkTransform.GetInterpolatedPosRot(out pos1, out rot1);
          Matrix4x4 matrix4x4 = Matrix4x4.TRS(pos1, rot1, Vector3.one);
          if (syncPosition)
            pos = matrix4x4.MultiplyPoint3x4(vector3_3);
          if (syncRot)
            rot = quaternion1 * Quaternion.LookRotation((Vector3) matrix4x4.GetColumn(2), (Vector3) matrix4x4.GetColumn(1));
        }
      }
      else if (this.TransformSpace == TransformSpace.World)
      {
        if (syncPosition)
          pos = vector3_3;
        if (syncRot)
          rot = quaternion1;
      }
      else
      {
        if (syncPosition)
          pos = this.transform.parent.TransformPoint(vector3_3);
        if (syncRot)
          rot = this.transform.parent.rotation * quaternion1;
      }
    }
    else
    {
      if (syncPosition)
        pos = vector3_3;
      if (syncRot)
        rot = quaternion1;
    }
    return true;
  }

  private void ExecuteTeleport(
    bool syncPos,
    bool syncRot,
    ref Vector3 pos,
    ref Quaternion rot,
    Vector3 targetPos,
    Quaternion targetRot)
  {
    if (this._errorCorrector != null)
      this._errorCorrector.TransformErrorCorrector.Init(this.transform.position, this.transform.rotation);
    if (syncPos)
      pos = targetPos;
    if (!syncRot)
      return;
    rot = targetRot;
  }

  public override void OnBecameInterested()
  {
    this._becameInterestedTick = this.Engine.AuthoritativeTick;
  }

  public override unsafe void NetcodeIntoGameEngine()
  {
    bool flag = (this.Settings & NetworkTransformRepConditions.CompressRotationAggressively) == NetworkTransformRepConditions.CompressRotationAggressively;
    if (this.TransformSpace == TransformSpace.Local)
    {
      if (this._syncPosition)
        this._trans.localPosition = NetickUnityUtils.GetVector3(this.StatePtr, this._posPrecision);
      if (this._syncRot)
        this._trans.localRotation = !flag ? NetickUnityUtils.GetQuaternion(this.StatePtr + 3, this._rotPrecision) : NetickUnityUtils.GetQuaternionCompressed(this.StatePtr + 3);
    }
    else
    {
      NetworkObject parent = this.Object.Parent;
      NetworkTransform networkTransform = (NetworkTransform) null;
      if ((UnityEngine.Object) parent != (UnityEngine.Object) null)
        networkTransform = parent.AttachedNetworkTransform;
      if ((UnityEngine.Object) networkTransform != (UnityEngine.Object) null)
      {
        Vector3 pos = networkTransform._syncPosition ? networkTransform.Position : networkTransform.transform.position;
        Quaternion rotation = networkTransform._syncRot ? networkTransform.Rotation : networkTransform.transform.rotation;
        Quaternion q = rotation;
        Vector3 localScale = networkTransform.transform.localScale;
        Matrix4x4 inverse = Matrix4x4.TRS(pos, q, localScale).inverse;
        if (this._syncPosition)
        {
          Vector3 vector3 = NetickUnityUtils.GetVector3(this.StatePtr, this._posPrecision);
          this._trans.localPosition = inverse.MultiplyPoint3x4(vector3);
        }
        if (this._syncRot)
          this._trans.localRotation = (flag ? NetickUnityUtils.GetQuaternionCompressed(this.StatePtr + 3) : NetickUnityUtils.GetQuaternion(this.StatePtr + 3, this._rotPrecision)) * Quaternion.Inverse(rotation);
      }
      else
      {
        if (this._syncPosition)
          this._trans.position = NetickUnityUtils.GetVector3(this.StatePtr, this._posPrecision);
        if (this._syncRot)
          this._trans.rotation = !flag ? NetickUnityUtils.GetQuaternion(this.StatePtr + 3, this._rotPrecision) : NetickUnityUtils.GetQuaternionCompressed(this.StatePtr + 3);
      }
    }
    if (!this.IsClient)
      return;
    this.Entity.Position = *(Vector3*) &this._trans.position;
  }

  public override unsafe void GameEngineIntoNetcode()
  {
    if (!this._trans.hasChanged)
      return;
    bool isServer = this.Engine.IsServer;
    int* numPtr1 = (int*) &new TransformBuffer();
    Vector3 position = this._trans.position;
    Quaternion rotation = this._trans.rotation;
    bool flag1 = (double) position.x != (double) this._lastPos.x || (double) position.y != (double) this._lastPos.y || (double) position.z != (double) this._lastPos.z;
    bool flag2 = (double) rotation.x != (double) this._lastRot.x || (double) rotation.y != (double) this._lastRot.y || (double) rotation.z != (double) this._lastRot.z || (double) rotation.w != (double) this._lastRot.w;
    this._lastPos = position;
    this._lastRot = rotation;
    if (this._syncRot && (flag2 || !isServer))
    {
      if ((this.Settings & NetworkTransformRepConditions.CompressRotationAggressively) == NetworkTransformRepConditions.CompressRotationAggressively)
        NetickUnityUtils.SetQuaternionCompressed(numPtr1, this.TransformSpace == TransformSpace.Local ? this._trans.localRotation : this._trans.rotation);
      else
        NetickUnityUtils.SetQuaternion(numPtr1, this.TransformSpace == TransformSpace.Local ? this._trans.localRotation : this._trans.rotation, this._rotInversePrecision);
      this.Entity.SetState(numPtr1, this.StatePtr + 3, 4, 0, 0);
    }
    if (this._syncPosition && (flag1 || !isServer))
    {
      Vector3 vector3 = this.TransformSpace == TransformSpace.Local ? this._trans.localPosition : position;
      int* numPtr2 = (int*) &vector3;
      NetickUnityUtils.SetVector3(numPtr2, vector3, this._posInversePrecision);
      this.Entity.SetState(numPtr2, this.StatePtr, 3, 0, 0);
    }
    if (!isServer || !this.Engine.IsIMEnabled || !this.UseForAOIPosition)
      return;
    this.Entity.Move(*(Vector3*) &position);
  }
}
